package com.example.yx1.demo28;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class A28 {

    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(WebConfig.class);


        ServletInvocableHandlerMethod handlerMethod =
                new ServletInvocableHandlerMethod(
                        context.getBean(WebConfig.MyController.class),
                        WebConfig.MyController.class.getMethod("user"));
        handlerMethod.setDataBinderFactory(new ServletRequestDataBinderFactory(Collections.emptyList(),null));
        handlerMethod.setParameterNameDiscoverer(new DefaultParameterNameDiscoverer());
        handlerMethod.setHandlerMethodArgumentResolvers(getThese(context));
        handlerMethod.setHandlerMethodReturnValueHandlers(getReturnValueHandler());


        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();

        ModelAndViewContainer mav = new ModelAndViewContainer();

        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        handlerMethod.invokeAndHandle(webRequest, mav);


        System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
        context.close();
    }

    public static HandlerMethodReturnValueHandlerComposite getReturnValueHandler() {
        HandlerMethodReturnValueHandlerComposite composite = new HandlerMethodReturnValueHandlerComposite();
        composite.addHandler(new ModelAndViewMethodReturnValueHandler());
        composite.addHandler(new ViewNameMethodReturnValueHandler());
        composite.addHandler(new ServletModelAttributeMethodProcessor(false));

        List<HttpMessageConverter<?>> list = new ArrayList<>();
        list.add(new MappingJackson2HttpMessageConverter());
        composite.addHandler(new HttpEntityMethodProcessor(list));
        composite.addHandler(new HttpHeadersReturnValueHandler());
        composite.addHandler(new RequestResponseBodyMethodProcessor(list));
        composite.addHandler(new ServletModelAttributeMethodProcessor(true));
        return composite;
    }

    public static HandlerMethodArgumentResolverComposite getThese(AnnotationConfigApplicationContext context) {
        HandlerMethodArgumentResolverComposite composite = new HandlerMethodArgumentResolverComposite();
        composite.addResolvers(
                new RequestParamMethodArgumentResolver(context.getDefaultListableBeanFactory(),false),
                new PathVariableMethodArgumentResolver(),
                new RequestHeaderMethodArgumentResolver(context.getDefaultListableBeanFactory()),
                new ServletCookieValueMethodArgumentResolver(context.getDefaultListableBeanFactory()),
                new ExpressionValueMethodArgumentResolver(context.getDefaultListableBeanFactory()),
                new ServletRequestMethodArgumentResolver(),
                new ServletResponseMethodArgumentResolver(),
                new ServletModelAttributeMethodProcessor(false),//必须有 @ModelAttribute
                new ServletModelAttributeMethodProcessor(true),//省略 @ModelAttribute,优先走上面的
                new RequestParamMethodArgumentResolver(context.getDefaultListableBeanFactory(), true));
        return composite;
    }
}
